home *** CD-ROM | disk | FTP | other *** search
/ Stone Design / Stone Design.iso / Stone_Friends / NeXT-Icons / next-icon@gun.com / Apps / ImagePortfolio / apputils.subproj / ParseString.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-03  |  12.5 KB  |  510 lines

  1. // -----------------------------------------------------------------------------------------
  2. // general string/table functions
  3. // author: Martin D. Flynn
  4. // -------------------------------------------------------------------------------------
  5. // Permission is granted to freely redistribute this source code, and to use fragments
  6. // of this code in your own applications if you find them to be useful.  This class,
  7. // along with the source code, come with no warranty of any kind, and the user assumes
  8. // all responsibility for its use.
  9. // -----------------------------------------------------------------------------------------
  10. extern "Objective-C" {
  11. #import <stdio.h>
  12. #import <string.h>
  13. #import <ctype.h>
  14. #import <libc.h>
  15. #import <pwd.h>
  16. #import <sys/types.h>
  17. #import <sys/stat.h>
  18. #import <sys/param.h>
  19. #import <sys/dir.h>
  20. }
  21.  
  22. #import "ParseString.h"
  23.  
  24. // -----------------------------------------------------------------------------------------
  25. // misc constants
  26. static int            instId = 0;
  27. static char            *lvalNull = (char*)NULL;
  28.  
  29. // -----------------------------------------------------------------------------------------
  30. // new strings
  31.  
  32. /* allocate new copy of string */
  33. inline char *new_String(const char *s)
  34. {
  35.     return s? strcpy(new char[strlen(s) + 1], s) : (char*)NULL;
  36. }
  37.  
  38. /* return directory table */
  39. #define    BLOCK_SIZE    1024
  40. static char *new_ReadDirectoryList(const char *path)
  41. {
  42.     int                d, ls, listSize;
  43.     DIR             *dirp;
  44.     char            *dirs, *list;
  45.     struct direct    *dp;
  46.     
  47.     /* open directory */
  48.     if (!path || !*path) return (char*)NULL;
  49.     if (!(dirp = opendir(path))) return (char*)NULL;
  50.     
  51.     /* skip '.' & '..' */
  52.     readdir(dirp);    // skip "."
  53.     readdir(dirp);    // skip ".."
  54.     
  55.     /* read directory entries */
  56.     dirs = (char*)malloc(ls = listSize = BLOCK_SIZE);
  57.     for (*dirs = 0, d = 0; dp = readdir(dirp); d += dp->d_namlen) {
  58.         while (d + dp->d_namlen + 2 > ls) ls += BLOCK_SIZE;
  59.         if (ls > listSize) dirs = (char*)realloc(dirs, (listSize = ls));
  60.         if (d) dirs[d++] = ' '; 
  61.         *(strncpy(&dirs[d], dp->d_name, dp->d_namlen) + dp->d_namlen) = 0;
  62.     }
  63.     closedir(dirp);
  64.  
  65.     /* allocate/return list */
  66.     list = new_String(dirs);
  67.     free(dirs);
  68.     return list;
  69.     
  70. }
  71. #undef BLOCK_SIZE
  72.  
  73. /* read/return file contents */
  74. static char *new_ReadFileList(const char *fileName)
  75. {
  76.     char        *newlist = (char*)NULL;
  77.     FILE        *fhnd;
  78.     struct stat    st;
  79.     
  80.     /* stat file */
  81.     if (stat(fileName, &st) != 0) return (char*)NULL;
  82.     
  83.     /* check for file directory */
  84.     if (st.st_mode & S_IFDIR) return new_ReadDirectoryList(fileName);
  85.     
  86.     /* open/read file contents */
  87.     fhnd = fopen(fileName, "r");
  88.     if (fhnd) {
  89.         int fLen = st.st_size;
  90.         char list[fLen + 1];
  91.         memset(list, 0, fLen + 1);
  92.         if (fread(list, 1, fLen, fhnd) == fLen) {
  93.             char *x, *z;
  94.             for (x = z = list; x < list + fLen;) {
  95.                 for (; (x < list + fLen) && (*x <= ' '); x++);
  96.                 if (x >= list + fLen) break;
  97.                 if (z != list) *z++ = ' ';
  98.                 for (;(x < list + fLen) && (*x > ' '); z++, x++) if (z != x) *z = *x;
  99.             }
  100.             *z = 0;
  101.             newlist = new_String(list);
  102.         }
  103.         fclose(fhnd);
  104.     }
  105.     
  106.     return newlist;
  107. }
  108.  
  109. // -----------------------------------------------------------------------------------------
  110. // constructors/destructor
  111.  
  112. /* empty contructor */
  113. ParseString::ParseString()
  114. {
  115.     instanceId = instId++;
  116.     parseList = (char*)NULL;
  117.     parseTable = (char**)NULL;
  118. }
  119.  
  120. /* copy constructor */
  121. ParseString::ParseString(const ParseString &other)
  122. {
  123.     instanceId = instId++;
  124.     parseList = other.newUnparsedList();
  125.     parseTable = this->_parseList(parseList);
  126. }
  127.  
  128. /* list string contructor */
  129. ParseString::ParseString(const char *list)
  130. {
  131.     instanceId = instId++;
  132.     parseList = list? new_String(list) : (char*)NULL;
  133.     parseTable = this->_parseList(parseList);
  134. }
  135.  
  136. /* appended list constructor */
  137. ParseString::ParseString(const char *list1, const char *list2)
  138. {
  139.     instanceId = instId++;
  140.     parseList = this->_concatLists(list1, list2);
  141.     parseTable = this->_parseList(parseList);
  142. }
  143.  
  144. /* destructor */
  145. virtual ParseString::~ParseString()
  146. {
  147.     instanceId = -instanceId;
  148.     this->_clean();
  149. }
  150.  
  151. // -----------------------------------------------------------------------------------------
  152. // operator overloading
  153.  
  154. /* pipe from file name assignment "<<=" operator */
  155. /* Note: unfortunately 'ParseString ps <<= "filename"' isn't allowed. */
  156. ParseString & ParseString::operator<<=(const char *fileName)
  157. {
  158.     this->_clean();
  159.     parseList = new_ReadFileList(fileName);
  160.     parseTable = this->_parseList(parseList);
  161.     return *this;
  162. }
  163.  
  164. /* assignment "=" operator */
  165. ParseString & ParseString::operator=(const ParseString &other)
  166. {
  167.     if (&other == this) return *this;    // self assignment
  168.     this->_clean();
  169.     parseList = other.newUnparsedList();
  170.     parseTable = this->_parseList(parseList);
  171.     return *this;
  172. }
  173.  
  174. /* assignment "=" operator */
  175. ParseString & ParseString::operator=(const char *list)
  176. {
  177.     this->_clean();
  178.     parseList = new_String(list);
  179.     parseTable = this->_parseList(parseList);
  180.     return *this;
  181. }
  182.  
  183. /* "+=" operator (append objects) */
  184. ParseString & ParseString::operator+=(const ParseString &second)
  185. {
  186.     char    *ptr1 = this->newUnparsedList();
  187.     char    *ptr2 = second.newUnparsedList();
  188.     this->_clean();
  189.     parseList = this->_concatLists(ptr1, ptr2);
  190.     parseTable = this->_parseList(parseList);
  191.     delete ptr1;
  192.     delete ptr2;
  193.     return *this;
  194. }
  195.  
  196. /* "+=" operator (append objects) */
  197. ParseString & ParseString::operator+=(const char *list)
  198. {
  199.     char    *ptr1 = this->newUnparsedList();
  200.     this->_clean();
  201.     parseList = this->_concatLists(ptr1, list);
  202.     parseTable = this->_parseList(parseList);
  203.     delete ptr1;
  204.     return *this;
  205. }
  206.  
  207. /* "|=" operator (append objects) */
  208. ParseString & ParseString::operator|=(const ParseString &second)
  209. {
  210.     ParseString    ps(second);
  211.     char        **stbl = ps.table();
  212.     if (!stbl) return ParseString(*this);
  213.     char *ptr1 = this->newUnparsedList();
  214.     for (int i = 0; stbl[i]; i++) if (this->indexTo(stbl[i]) >= 0) stbl[i] = "";
  215.     char *ptr2 = ps.newUnparsedList();
  216.     this->_clean();
  217.     parseList = this->_concatLists(ptr1, ptr2);
  218.     parseTable = this->_parseList(parseList);
  219.     delete ptr1;
  220.     delete ptr2;
  221.     return *this;
  222. }
  223.  
  224. /* "|=" operator (append objects) */
  225. ParseString & ParseString::operator|=(const char *list)
  226. {
  227.     ParseString    ps(list);
  228.     char        **stbl = ps.table();
  229.     if (!stbl) return ParseString(*this);
  230.     char *ptr1 = this->newUnparsedList();
  231.     for (int i = 0; stbl[i]; i++) if (this->indexTo(stbl[i]) >= 0) stbl[i] = "";
  232.     char *ptr2 = ps.newUnparsedList();
  233.     this->_clean();
  234.     parseList = this->_concatLists(ptr1, ptr2);
  235.     parseTable = this->_parseList(parseList);
  236.     delete ptr1;
  237.     delete ptr2;
  238.     return *this;
  239. }
  240.  
  241. /* "+" operator (append objects) */
  242. ParseString ParseString::operator+(const ParseString &second) const
  243. {
  244.     char    *ptr1 = this->newUnparsedList();
  245.     char    *ptr2 = second.newUnparsedList();
  246.     ParseString    ps(ptr1, ptr2);
  247.     delete ptr1;
  248.     delete ptr2;
  249.     return ps;
  250. }
  251.  
  252. /* "+" operator (append objects) */
  253. ParseString ParseString::operator+(const char *list) const
  254. {
  255.     char    *ptr1 = this->newUnparsedList();
  256.     ParseString    ps(ptr1, list);
  257.     delete ptr1;
  258.     return ps;
  259. }
  260.  
  261. /* "|" operator (merge objects) */
  262. ParseString ParseString::operator|(const ParseString &second) const
  263. {
  264.     ParseString    ps(second);
  265.     char        **stbl = ps.table();
  266.     
  267.     /* return copy of *this, if second contains no table */
  268.     if (!stbl) return ParseString(*this);
  269.     
  270.     /* remove non-unique entries */
  271.     char *ptr1 = this->newUnparsedList();
  272.     for (int i = 0; stbl[i]; i++) if (this->indexTo(stbl[i]) >= 0) stbl[i] = "";
  273.     char *ptr2 = ps.newUnparsedList();
  274.     ParseString    nps(ptr1, ptr2);
  275.     delete ptr1;
  276.     delete ptr2;
  277.     
  278.     return nps;
  279. }
  280.  
  281. /* "|" operator (merge objects) */
  282. ParseString ParseString::operator|(const char *list) const
  283. {
  284.     ParseString    ps(list);
  285.     char        **stbl = ps.table();
  286.     
  287.     /* return copy of *this, if second contains no table */
  288.     if (!stbl) return ParseString(*this);
  289.     
  290.     /* remove non-unique entries */
  291.     char *ptr1 = this->newUnparsedList();
  292.     for (int i = 0; stbl[i]; i++) if (this->indexTo(stbl[i]) >= 0) stbl[i] = "";
  293.     char *ptr2 = ps.newUnparsedList();
  294.     ParseString    nps(ptr1, ptr2);
  295.     delete ptr1;
  296.     delete ptr2;
  297.     
  298.     return nps;
  299. }
  300.  
  301. /* "[]" operator (reference items in table) */
  302. char * & ParseString::operator[](int ndx) const
  303. {
  304.     char    **tbl = this->table();
  305.     if (!tbl) { lvalNull = (char*)NULL; return lvalNull; }
  306.     return tbl[ndx];
  307. }
  308.  
  309. /* "()" operator (return index to item in table) */
  310. int ParseString::operator()(const char *item) const
  311. {
  312.     return this->indexTo(item);
  313. }
  314.  
  315. // -----------------------------------------------------------------------------------------
  316. // member functions
  317.  
  318. /* print table contents */
  319. void ParseString::print() const
  320. {
  321.     int        c;
  322.     printf("Print ParseString table: (%d)\n", instanceId);
  323.     if (!this->table()) return;
  324.     for (c = 0; (*this)[c]; c++) printf("  %s\n", (*this)[c]);
  325. }
  326.  
  327. /* return table array */
  328. char ** ParseString::table() const
  329. {
  330.     return parseTable? parseTable : (char**)NULL;
  331. }
  332.  
  333. /* return item count */
  334. int ParseString::count() const
  335. {
  336.     int        c;
  337.     char    **tbl = this->table();
  338.     if (!tbl) return 0;
  339.     for (c = 0; tbl[c]; c++);
  340.     return c;
  341. }
  342.  
  343. /* return table string length */
  344. int ParseString::unparsedLength() const
  345. {
  346.     return this->_unparsedLength(this->table());
  347. }
  348.  
  349. /* unparse table */
  350. char * ParseString::getUnparsedList(char *list, int listLen) const
  351. {
  352.     return this->_unparseList(this->table(), list, listLen);
  353. }
  354.  
  355. /* return new unparsed list */
  356. char * ParseString::newUnparsedList() const
  357. {
  358.     return this->_newUnparsedList(this->table());
  359. }
  360.  
  361. /* return index of specified item */
  362. int ParseString::indexTo(const char *entry) const
  363. {
  364.     int        i;
  365.     char    **tbl = this->table();
  366.     if (!tbl) return -1;
  367.     for (i = 0; tbl[i]; i++) if (!strcmp(tbl[i], entry)) return i;
  368.     return -1;
  369. }
  370.  
  371. /* return entry at index */
  372. char * ParseString::entryAt(int ndx) const
  373. {
  374.     char    **tbl = this->table();
  375.     if (!tbl) return (char*)NULL;
  376.     return tbl[ndx];
  377. }
  378.  
  379. // -----------------------------------------------------------------------------------------
  380. // sorting
  381.  
  382. /* sort compare routine */
  383. #define    TOLOWER(C)    (isupper(C)? tolower(C) : (C))
  384. virtual int ParseString::_sortCompare(char *p, char *q) const
  385. {
  386.     register int i, j, d;
  387.     for (; *p && *q; ) {
  388.         if (isdigit(*p) && isdigit(*q)) {
  389.             for (i = 0; isdigit(*p); i = i * 10 + *p++ - '0');
  390.             for (j = 0; isdigit(*q); j = j * 10 + *q++ - '0');
  391.             if (i != j) return i - j;
  392.             continue;
  393.         }
  394.         if (d = TOLOWER(*p) - TOLOWER(*q)) return d;
  395.         p++, q++;
  396.     }
  397.     return *p - *q;
  398. }
  399. #undef    TOLOWER
  400.  
  401. /* sort a string table (simple selection sort) */
  402. int ParseString::sort(int order = 0)
  403. {
  404.     char    **tbl = this->table();
  405.     if (!tbl) return 0;
  406.     for (int i = 0; tbl[i]; i++) {
  407.         for (int j = i + 1; tbl[j]; j++) {
  408.             int ri = !order? i : j;
  409.             int rj = !order? j : i;
  410.             if (this->_sortCompare(tbl[ri], tbl[rj]) > 0) {
  411.                 char *temp = tbl[ri];
  412.                 tbl[ri] = tbl[rj];
  413.                 tbl[rj] = temp;
  414.             }
  415.         }
  416.     }
  417.     return 1;
  418. }
  419.  
  420. // -----------------------------------------------------------------------------------------
  421. // private functions
  422.  
  423. /* clean house */
  424. void ParseString::_clean()
  425. {
  426.     if (parseList) { delete parseList; parseList = (char*)NULL; }
  427.     if (parseTable) { delete parseTable; parseTable = (char**)NULL; }
  428. }
  429.  
  430. /* concat lists */
  431. char * ParseString::_concatLists(const char *list1, const char *list2)
  432. {
  433.     const char    *l1 = list1? list1 : "", *l2 = list2? list2 : "";
  434.     char        *newList = new char[(strlen(l1) + 1) + (strlen(l2) + 1)];
  435.     sprintf(newList, "%s %s", l1, l2);
  436.     return newList;
  437. }
  438.  
  439. /* parse table */
  440. char ** ParseString::_parseList(char *list)
  441. {
  442.     int        c, n;
  443.     char    **tbl, *r;
  444.  
  445.     /* check string */
  446.     if (!list) return (char**)NULL;        // no string to parse
  447.  
  448.     /* skip whitespace in list */
  449.     for (;isspace(*list);) list++;
  450.     if (!*list) return (char**)NULL;
  451.  
  452.     /* count items in table */
  453.     c = 0;
  454.     r = list;
  455.     while (isspace(*r)) r++;
  456.     while (*r) {
  457.         c++;
  458.         while (*r && !isspace(*r)) r++;    // skip value
  459.         while (isspace(*r)) r++;        // skip white
  460.     }
  461.     c++; // include NULL terminator
  462.     tbl = new char*[c];
  463.     memset(tbl, 0, c * sizeof(tbl[0]));
  464.     
  465.     /* fill table */
  466.     for (n = 0, r = list; *r;) {
  467.         tbl[n++] = r;
  468.         while (*r && !isspace(*r)) r++;
  469.         while (isspace(*r)) *r++ = 0;
  470.     }
  471.     
  472.     /* return the table */
  473.     return tbl;
  474.  
  475. }
  476.  
  477. /* return unparsed length of specified table */
  478. int ParseString::_unparsedLength(const char **tbl) const
  479. {
  480.     int        i, len;
  481.     if (!tbl) return -1;
  482.     for (i = 0, len = 0; tbl[i]; i++) len += strlen(tbl[i]) + 1;
  483.     return len - 1;
  484. }
  485.  
  486. /* unparse list */
  487. char * ParseString::_unparseList(char **tbl, char *list, int listLen) const
  488. {
  489.     int        i;
  490.     char    *lp;
  491.     if (!tbl) return (char*)NULL;
  492.     *list = 0;
  493.     for (lp = list, i = 0; tbl[i]; i++) {
  494.         if (lp + strlen(tbl[i]) + 1 - list > listLen) break;    // overflow
  495.         if ((lp > list) && (*(lp - 1) != ' ')) *lp++ = ' ';
  496.         strcpy(lp, tbl[i]);
  497.         lp += strlen(lp);
  498.     }
  499.     return list;
  500. }
  501.  
  502. /* return new unparsed list */
  503. char * ParseString::_newUnparsedList(char **tbl) const
  504. {
  505.     if (!tbl) return (char*)NULL;
  506.     int listLen = this->_unparsedLength(tbl) + 1;
  507.     char *list = new char[listLen];
  508.     return this->_unparseList(tbl, list, listLen);
  509. }
  510.